package top.rish.rib.base.config;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.snack.ONode;
import org.noear.snack.core.Options;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.serialization.snack3.SnackRenderFactory;
import top.rish.rib.base.service.DictTranslatorService;
import top.rish.rib.base.ware.Dict;
import top.rish.rib.base.ware.DesireEntity;
import top.rish.rib.base.ware.EnumLabel;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Configuration
@Slf4j
public class DictTranslatorConfig {


    @Inject
    DictTranslatorService dictTranslatorService;


    private boolean isPrimitiveType(Class<?> clazz) {
        return  (
                int.class.isAssignableFrom(clazz)
                || long.class.isAssignableFrom(clazz)
                || float.class.isAssignableFrom(clazz)
                || boolean.class.isAssignableFrom(clazz)
                || double.class.isAssignableFrom(clazz)
                || byte.class.isAssignableFrom(clazz)
                || char.class.isAssignableFrom(clazz)
                || short.class.isAssignableFrom(clazz)
                || Number.class.isAssignableFrom(clazz)
                || String.class.isAssignableFrom(clazz)
                || Boolean.class.isAssignableFrom(clazz)
                || Character.class.isAssignableFrom(clazz)
                || Date.class.isAssignableFrom(clazz)
                || LocalDate.class.isAssignableFrom(clazz)
                || LocalDateTime.class.isAssignableFrom(clazz)
         );
    }

    private Map<String,Object> dictEntityFieldTranslator(Object entity,Options options) {
        Map<String,Object> rel = new LinkedHashMap<>();
        List<Field> fields = Arrays.stream(ReflectUtil.getFields(entity.getClass()))
                .filter(fx ->
                        !Modifier.isStatic(fx.getModifiers()) && !Modifier.isTransient(fx.getModifiers())
                ).sorted(Comparator.comparing(Field::getName)).toList();
        for (Field field : fields) {
            String fieldName = field.getName();
            Object fieldValue = ReflectUtil.getFieldValue(entity, field);
            rel.put(fieldName,  ONode.loadObj(fieldValue,options));
            if (field.isAnnotationPresent(Dict.class)) {
                Dict d = field.getAnnotation(Dict.class);
                String table = d.table();
                String dict = d.dict();
                String key = d.key();
                String label = d.label();
                try{
                    String labelText = null;
                    if (this.isPrimitiveType(field.getType())) {
                        if (ObjectUtil.isNotEmpty(dict)) {
                            if(ObjectUtil.isEmpty(key)){
                                key = "dict_code";
                            }
                            if(ObjectUtil.isEmpty(label)){
                                label = "dict_value";
                            }
                            labelText = dictTranslatorService
                                    .getLabelFromDictTable(dict,key,label,fieldValue);

                        } else if (ObjectUtil.isNotEmpty(table)) {
                            if(ObjectUtil.isEmpty(key)){
                                key = "id";
                            }
                            if(ObjectUtil.isEmpty(label)){
                                label = "name";
                            }
                            labelText = dictTranslatorService
                                    .getLabelFromBizTable(table,key,label,fieldValue);
                        }
                    }
                    rel.put(fieldName + "$Dict", ONode.load(labelText,options));
                }catch (Exception e){
                    log.error(e.getMessage(),e);
                    e.printStackTrace();
                }
            }else if(EnumLabel.class.isAssignableFrom(field.getType())){
                if(ObjectUtil.isNotEmpty(fieldValue)){
                    EnumLabel ei = (EnumLabel) fieldValue;
                    rel.put(fieldName + "$Enum",ei.getLabel());
                }
            }
        }

        return rel;
    }

    @Bean
    public void dictTranslator(@Inject SnackRenderFactory factory) {
        factory.addConvertor(Date.class, s ->
                DateUtil.format(s,"yyyy-MM-dd HH:mm:ss.SSS")
        );
        factory.addConvertor(LocalDate.class, s ->
                LocalDateTimeUtil.format(s,"yyyy-MM-dd")
        );
        factory.addConvertor(LocalTime.class, s ->
                DateTimeFormatter.ofPattern("HH:mm:ss").format(s)
        );
        factory.addConvertor(LocalDateTime.class, s -> {
            return LocalDateTimeUtil.format(s,"yyyy-MM-dd HH:mm:ss.SSS");
        });

        Options options = factory.config();
        factory.addEncoder(DesireEntity.class, (entity, node) -> {
            if (entity != null) {
                Map<String,Object> map =  this.dictEntityFieldTranslator(entity,options);
                if(!map.isEmpty()){
                    node.setAll(map);
                }
            } else {
                node.asObject();
            }
        });

    }
}